//
// Created by tys on 2017/10/26.
//

#include <log.h>
#include <pthread.h>
#include "include/AudioMedia.h"

int getPcm(AudioMedia *pMedia);

extern "C" {
#include <libavutil/time.h>
}

AudioMedia::AudioMedia() {
    LOG_E("--", "%s\n", "Audio构造函数");
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
}

AudioMedia::~AudioMedia() {
    LOG_E("--", "%s\n", "Audio析构函数");
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    if (out_buf)
        av_free(out_buf);
    if (swr_ctx)
        swr_free(&swr_ctx);
}

void AudioMedia::put(AVPacket *packet) {
    LOG_I("--", "%s\n", "音频入队列");
    pthread_mutex_lock(&mutex);
    queue.push(av_packet_clone(packet));
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}

//如何时生产，消费达到平衡？训不需要加入最好队列数限制，保证内存稳定
void AudioMedia::get(AVPacket **packet) {
    pthread_mutex_lock(&mutex);
    if (!queue.empty()) {
        LOG_I("---", "%s", "取音频数据播放");
        *packet = queue.front();
        queue.pop();
    } else {
        LOG_E("---", "%s", "waiting");//数据队列不为空时
        pthread_cond_wait(&cond, &mutex);
        if (!queue.empty()) {
            *packet = queue.front();
            queue.pop();
        }
    }
    pthread_mutex_unlock(&mutex);
}

void AudioMedia::setIsPlay(bool isPlay) {
    AudioMedia::isPlay = isPlay;
}


//只要喇叭一读完  就会回调此函数，解析packet添加pcm数据到缓冲区
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
    AudioMedia *audio = (AudioMedia *) context;
    int size = getPcm(audio);
    if (size > 0) {
        // 每秒钟音频播放的字节数 sample_rate * channels * sample_format(一个sample占用的字节数) AV_SAMPLE_FMT_S16
        double time = size/((double) audio->dst_rate * audio->dst_ch_nb * 2);//sample format是16位的无符号整型，占用2个字节
        audio->clock += time;
        (*bq)->Enqueue(bq, audio->out_buf, size);
        LOG_E("---", "播放 %d , time:%f", audio->queue.size(), time);
    } else if(!audio->isPlay){
        LOG_E("---", "播放 状态 %d\n", audio->isPlay);//opensl es 播放线程退出，资源回收
    }

}

int getPcm(AudioMedia *audio) {
    int got_frame;
    int size = 0;
    AVPacket *packet;
    AVFrame *frame = av_frame_alloc();
    while (audio->isPlay) {
        audio->get(&packet);
        if (packet->pts != AV_NOPTS_VALUE) {
            audio->clock = av_q2d(audio->time_base) * packet->pts;
        LOG_E("111 audio", "pts:%d,pts*base:%f, duration(next_pts - this_pts):%d, dts:%d\n",
              packet->pts,av_q2d(audio->time_base) * packet->pts, packet->duration, packet->dts);
        }
//      解码  mp3   编码格式frame----pcm   frame
        avcodec_decode_audio4(audio->dec_ctx, frame, &got_frame, packet);
        if (got_frame) {
            swr_convert(audio->swr_ctx, &audio->out_buf, audio->dst_rate * 2,
                        (const uint8_t **) frame->data,
                        frame->nb_samples);
            size = av_samples_get_buffer_size(NULL, audio->dst_ch_nb, frame->nb_samples,
                                              audio->dst_sample_fmt, 1);
            break;
        } else {
            LOG_E("IIIIIIIIIIIII", "got_frame=%d", 0);
        }
        av_free(packet);
    }
    av_frame_free(&frame);
    return size;
}

void *playAudio(void *arg) {
    LOG_E("---", "%s， tid:%ld\n", "音频播放线程", pthread_self());
    AudioMedia *audio = (AudioMedia *) arg;
    //播放第一帧
    bqPlayerCallback(audio->bqPlayerBufferQueue, audio);
    return (void *) 0;
}

void AudioMedia::play() {
    isPlay = 1;
    initSwrCtx();

    initOpenSlEs();
    pthread_create(&thread_t_audio, NULL, playAudio, this);
    pthread_detach(thread_t_audio);
}

int AudioMedia::initOpenSlEs() { //具体使用NDK sample
    LOG_E("---", "%s\n", "initOpenSlEs");

    SLresult result;
    // 创建引擎engineObject
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    if (SL_RESULT_SUCCESS != result) {
        return 0;
    }
    // 实现引擎engineObject
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        return 0;
    }
    // 获取引擎接口engineEngine
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE,
                                           &engineEngine);
    if (SL_RESULT_SUCCESS != result) {
        return 0;
    }
    // 创建混音器outputMixObject
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0,
                                              0, 0);
    if (SL_RESULT_SUCCESS != result) {
        return 0;
    }
    // 实现混音器outputMixObject
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) {
        return 0;
    }
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,
                                              &outputMixEnvironmentalReverb);
    const SLEnvironmentalReverbSettings settings = SL_I3DL2_ENVIRONMENT_PRESET_DEFAULT;
    if (SL_RESULT_SUCCESS == result) {
        (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &settings);
    }


    //======================
    SLDataLocator_AndroidSimpleBufferQueue android_queue = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
                                                            2};
    SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1, SL_PCMSAMPLEFORMAT_FIXED_16,
                            SL_PCMSAMPLEFORMAT_FIXED_16,
                            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
                            SL_BYTEORDER_LITTLEENDIAN};
//   新建一个数据源 将上述配置信息放到这个数据源中
    SLDataSource slDataSource = {&android_queue, &pcm};
//    设置混音器
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};

    SLDataSink audioSnk = {&outputMix, NULL};
    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,
            /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};
    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
            /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};
    //先讲这个
    (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &slDataSource,
                                       &audioSnk, 2,
                                       ids, req);
    //初始化播放器
    (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);

//    得到接口后调用  获取Player接口
    (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);

//    注册回调缓冲区 //获取缓冲队列接口
    (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                    &bqPlayerBufferQueue);
    //缓冲接口回调
    (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
//    获取音量接口
    (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);

//    获取播放状态接口
    (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);


    return 1;


}

int AudioMedia::initSwrCtx() {
    LOG_E("---", "%s\n", "initSwsCtx");
    int ret;
    swr_ctx = swr_alloc();
    /* set options */
    int64_t src_ch_layout = dec_ctx->channel_layout;
    AVSampleFormat src_sample_fmt = dec_ctx->sample_fmt;
    int src_rate = dst_rate = dec_ctx->sample_rate;
    dst_ch_nb = av_get_channel_layout_nb_channels(dst_ch_layout);

    swr_alloc_set_opts(swr_ctx, dst_ch_layout, dst_sample_fmt, dst_rate,
                       src_ch_layout, src_sample_fmt, src_rate, 0, NULL);
    /* initialize the resampling context */
    if ((ret = swr_init(swr_ctx)) < 0) {
        LOG_E("AudioMedia", "%s", "Failed to initialize the resampling context %s\n",
              av_err2str(ret));
        goto end;
    }
    out_buf = (uint8_t *) av_malloc(dst_rate * 2);
    LOG_E("---", "%s, %d, 通道数:%d\n", "initSwsCtx end", dst_rate, dst_ch_nb);
    return ret;
    end:
    swr_free(&swr_ctx);
    return ret;

}




